package top.zhangjianyong.blog.utils;

import com.maxmind.geoip2.DatabaseReader;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import java.io.InputStream;

/**
 * GeoIP2 连接池管理器
 * 管理 ASN 和 City 两种类型的 DatabaseReader 连接池
 * 单例模式，确保全局唯一的管理器实例
 */
@Getter
@Slf4j
public class GeoIP2PoolManager {

    // 连接池配置
    private static final int DEFAULT_POOL_SIZE = 5;
    private static final int DEFAULT_WAIT_TIMEOUT = 1000; // 1秒

    /**
     * -- GETTER --
     * 获取 ASN 连接池
     */
    private final DatabaseReaderPool asnPool;
    /**
     * -- GETTER --
     * 获取 City 连接池
     */
    private final DatabaseReaderPool cityPool;

    // 单例实例
    private static volatile GeoIP2PoolManager instance;
    private static final Object INSTANCE_LOCK = new Object();

    /**
     * 获取连接池管理器单例实例
     */
    public static GeoIP2PoolManager getInstance() {
        if (instance == null) {
            synchronized (INSTANCE_LOCK) {
                if (instance == null) {
                    instance = new GeoIP2PoolManager();
                }
            }
        }
        return instance;
    }

    /**
     * 私有构造函数，防止外部实例化
     */
    private GeoIP2PoolManager() {
        log.info("初始化 GeoIP2 连接池管理器");

        // 创建 ASN 连接池
        this.asnPool = new DatabaseReaderPool(
            "ASN",
            DEFAULT_POOL_SIZE,
            DEFAULT_WAIT_TIMEOUT,
            this::createAsnReader
        );

        // 创建 City 连接池
        this.cityPool = new DatabaseReaderPool(
            "City",
            DEFAULT_POOL_SIZE,
            DEFAULT_WAIT_TIMEOUT,
            this::createCityReader
        );
    }

    /**
     * 获取 ASN DatabaseReader 实例
     *
     * @return DatabaseReader 实例，如果获取失败返回 null
     */
    public DatabaseReader getAsnReader() {
        return asnPool.getReader();
    }

    /**
     * 获取 City DatabaseReader 实例
     *
     * @return DatabaseReader 实例，如果获取失败返回 null
     */
    public DatabaseReader getCityReader() {
        return cityPool.getReader();
    }

    /**
     * 归还 ASN DatabaseReader 到池中
     *
     * @param reader DatabaseReader 实例
     */
    public void returnAsnReader(DatabaseReader reader) {
        asnPool.returnReader(reader);
    }

    /**
     * 归还 City DatabaseReader 到池中
     *
     * @param reader DatabaseReader 实例
     */
    public void returnCityReader(DatabaseReader reader) {
        cityPool.returnReader(reader);
    }

    /**
     * 创建 ASN DatabaseReader 实例
     *
     * @return DatabaseReader 实例，创建失败返回 null
     */
    private DatabaseReader createAsnReader() {
        try {
            InputStream inputStream = GeoIP2PoolManager.class.getClassLoader()
                .getResourceAsStream("GeoLite2-ASN.mmdb");
            if (inputStream == null) {
                log.error("未找到 GeoLite2-ASN.mmdb 文件，请确认已放置在 resources 目录下");
                return null;
            }
            return new DatabaseReader.Builder(inputStream).build();
        } catch (Exception e) {
            log.error("创建 ASN DatabaseReader 失败", e);
            return null;
        }
    }

    /**
     * 创建 City DatabaseReader 实例
     *
     * @return DatabaseReader 实例，创建失败返回 null
     */
    private DatabaseReader createCityReader() {
        try {
            InputStream inputStream = GeoIP2PoolManager.class.getClassLoader()
                .getResourceAsStream("GeoLite2-City.mmdb");
            if (inputStream == null) {
                log.error("未找到 GeoLite2-City.mmdb 文件，请确认已放置在 resources 目录下");
                return null;
            }
            return new DatabaseReader.Builder(inputStream).build();
        } catch (Exception e) {
            log.error("创建 City DatabaseReader 失败", e);
            return null;
        }
    }

    /**
     * 获取连接池管理器状态信息
     *
     * @return 连接池管理器状态字符串
     */
    public String getManagerStatus() {
        return String.format("GeoIP2 Pool Manager - %s, %s",
            asnPool.getPoolStatus(), cityPool.getPoolStatus());
    }

    /**
     * 获取 ASN 连接池状态
     *
     * @return ASN 连接池状态
     */
    public String getAsnPoolStatus() {
        return asnPool.getPoolStatus();
    }

    /**
     * 获取 City 连接池状态
     *
     * @return City 连接池状态
     */
    public String getCityPoolStatus() {
        return cityPool.getPoolStatus();
    }

    /**
     * 关闭连接池管理器，释放所有资源
     */
    public void shutdown() {
        log.info("关闭 GeoIP2 连接池管理器");

        // 关闭 ASN 连接池
        asnPool.shutdown();

        // 关闭 City 连接池
        cityPool.shutdown();

        log.info("GeoIP2 连接池管理器已关闭");
    }
} 